# sorting basics
values = [2, 5, 1, 4, 3]

# non-decreasing
values.sort()
print(values)

# non-increasing
values.sort(reverse=True)
print(values)

# sorted the origin list doesn't change
print(sorted(values))
print(values)

###########################
# key functions

values = [2, 5, 1, 4, 3]

# evens first
print(sorted(values, key=lambda x: x%2))

values = [(1, 3), (5, 4), (3, 2)]

# sort by the second value
print(sorted(values, key=lambda x: x[1]))

############################
# also key functions

values = [2, 5, 1, 4, 3]

# sort ord by values[i]
# I use it frequently in c++
ord = [i for i in range(5)]
ord.sort(key=lambda i: values[i])
print(ord) # [2, 0, 4, 3, 1]

##########################
# C++ compare, really weird

# returns -1 means x goes first
# x[1] as first key smaller goes first, x[0] as second key bigger goes first
from functools import cmp_to_key
def compare(x, y):
    if x[1] < y[1]:
        return -1
    elif x[1] > y[1]:
        return 1
    if x[0] > y[0]:
        return -1
    elif x[0] < y[0]:
        return 1
    return 0

values = [(1, 3), (5, 4), (3, 2), (1, 2)]
values.sort(key=cmp_to_key(compare))
print(values)

#########################
# overload operator `<` (__lt__)

class pair:
    def __init__(self, _first = 0, _second = 0):
        self.first = _first
        self.second = _second

    def __lt__(self, other):
        if self.second != other.second:
            return self.second < other.second
        return self.first > other.first

    # just for print, like to_string() in c++
    def __str__(self):
        return f'({self.first}, {self.second})'

    __repr__ = __str__

values = [pair(1, 3), pair(5, 4), pair(3, 2), pair(1, 2)]
values.sort()
# why print(values) doesn't work -> add rewrite __repr__
print(values)
